// Code file original author: Martin Lapierre, http://devinstinct.com

using System;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Configuration;
using EntLibContrib.Validation.Validators;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Common;

namespace EntLibContrib.Validation.Configuration
{
    /// <summary>
    /// Configuration object to describe an instance of class <see cref="TypeValidatorData"/>.
    /// </summary>
    /// <remarks>
    /// Spin-off of the TypeConversionValidatorData class.
    /// </remarks>
    public class TypeValidatorData : ValueValidatorData
    {
        private static readonly AssemblyQualifiedTypeNameConverter typeConverter = new AssemblyQualifiedTypeNameConverter();

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="TypeValidatorData"/> class.</para>
        /// </summary>
        public TypeValidatorData()
        { }

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="TypeValidatorData"/> class with a name.</para>
        /// </summary>
        /// <param name="name">The name for the instance.</param>
        public TypeValidatorData(string name)
            : base(name, typeof(TypeValidator<>))
        { }

        private const string TargetTypeNamePropertyName = "targetType";
        /// <summary>
        /// Gets or sets name of the type the represented <see cref="TypeValidator"/> must use for testing conversion.
        /// </summary>
        [ConfigurationProperty(TargetTypeNamePropertyName, IsRequired = true)]
        public string TargetTypeName
        {
            get { return (string)this[TargetTypeNamePropertyName]; }
            set { this[TargetTypeNamePropertyName] = value; }
        }

        /// <summary>
        /// Gets or sets the target element type.
        /// </summary>
        public Type TargetType
        {
            get { return (Type)typeConverter.ConvertFrom(TargetTypeName); }
            set { TargetTypeName = typeConverter.ConvertToString(value); }
        }

        /// <summary>
        /// Creates the <see cref="TypeValidator"/> described by the configuration object.
        /// </summary>
        /// <param name="notused">Not used.</param>
        /// <returns>The created <see cref="TypeValidator"/>.</returns>	
        protected override Validator DoCreateValidator(Type notused)
        {
            Type typeValidator = typeof(TypeValidator<>).MakeGenericType(TargetType);
            return Activator.CreateInstance(typeValidator, GetMessageTemplate(), Tag, Negated) as Validator;
        }

        /// <summary>
        /// Returns the message template for the represented validator.
        /// </summary>
        /// <remarks>
        /// Same as ValidatorData::GetMessageTemplate... internal
        /// The textual message is given precedence over the resource based mechanism.
        /// </remarks>
        string GetMessageTemplate()
        {
            if (!string.IsNullOrEmpty(this.MessageTemplate))
            {
                return this.MessageTemplate;
            }
            Type messageTemplateResourceType = this.GetMessageTemplateResourceType();
            if (null != messageTemplateResourceType)
            {
                return ResourceStringLoader.LoadString(messageTemplateResourceType.FullName,
                    this.MessageTemplateResourceName,
                    messageTemplateResourceType.Assembly);
            }

            return null;
        }

        /// <summary>
        /// Same as ValidatorData::GetMessageTemplateResourceType... private
        /// </summary>
        /// <returns></returns>
        private Type GetMessageTemplateResourceType()
        {
            if (!string.IsNullOrEmpty(this.MessageTemplateResourceTypeName))
            {
                return Type.GetType(this.MessageTemplateResourceTypeName);
            }

            return null;
        }
    }
}
